package com.imooc.pan.server.modules.recycle.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.imooc.pan.core.constants.RPanConstants;
import com.imooc.pan.core.exception.RPanBusinessException;
import com.imooc.pan.server.common.event.file.FilePhysicalDeleteEvent;
import com.imooc.pan.server.modules.file.context.QueryFileListContext;
import com.imooc.pan.server.modules.file.entity.RPanUserFile;
import com.imooc.pan.server.modules.file.enums.DelFlagEnum;
import com.imooc.pan.server.modules.file.service.RPanUserFileService;
import com.imooc.pan.server.modules.file.vo.RPanUserFileVo;
import com.imooc.pan.server.modules.recycle.context.DeleteContext;
import com.imooc.pan.server.modules.recycle.context.QueryRecycleFileListContext;
import com.imooc.pan.server.modules.recycle.context.RestoreContext;
import com.imooc.pan.server.common.event.file.FileRestoreEvent;
import com.imooc.pan.server.modules.recycle.service.RecycleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class RecycleServiceImpl implements RecycleService , ApplicationContextAware {
    @Autowired
    private RPanUserFileService rPanUserFileService;
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /**
     * 查询已删除的文件列表
     * @param context
     * @return
     */
    @Override
    public List<RPanUserFileVo> recycles(QueryRecycleFileListContext context) {
        QueryFileListContext queryContext = new QueryFileListContext();
        queryContext.setUserId(context.getUserId());
        queryContext.setDelFlag(DelFlagEnum.Yes.getCode());
        return rPanUserFileService.getFileList(queryContext);
    }

    /**
     * 删除的文件还原
     * 1. 检验文件还原的操作权限
     * 2. 检查文件是不是可以还原
     * 3. 执行文件还原操作
     * 4. 执行文件还原的后置操作
     * @param context
     */
    @Override
    public void restore(RestoreContext context) {
        checkRestorePermission(context);
        checkRestoreFilename(context);
        doRestore(context);
        afterRestore(context);
    }

    @Override
    public void delete(DeleteContext context) {
        checkFileDeletePermission(context);
        findAllFileRecords(context);
        doDelete(context);
        afterDelete(context);
    }

    /**
     * 执行删除的后置操作
     * @param context
     */
    private void afterDelete(DeleteContext context) {
        FilePhysicalDeleteEvent event = new FilePhysicalDeleteEvent(this, context.getAllRecords());
        applicationContext.publishEvent(event);
    }

    /**
     * 执行删除操作
     * @param context
     */
    private void doDelete(DeleteContext context) {
        List<Long> fileIdList = context.getFileIdList();
        if(!rPanUserFileService.removeByIds(fileIdList)){
            throw new RPanBusinessException("文件删除失败");
        }
    }

    /**
     * 递归查询所有子文件
     * @param context
     */
    private void findAllFileRecords(DeleteContext context) {
        List<RPanUserFile> records = context.getRecords();
        List<RPanUserFile> allRecords =  rPanUserFileService.findAllFileRecords(records);
        context.setAllRecords(allRecords);
    }

    /**
     * 校验文件删除的权限
     * @param context
     */
    private void checkFileDeletePermission(DeleteContext context) {
        QueryWrapper queryWrapper = Wrappers.query();
        queryWrapper.eq("user_id",context.getUserId());
        queryWrapper.in("file_id",context.getFileIdList());
        List<RPanUserFile> records = rPanUserFileService.list(queryWrapper);
        if (CollectionUtils.isEmpty(records) || records.size() != context.getFileIdList().size()) {
            throw new RPanBusinessException("您无权删除该文件");
        }
        context.setRecords(records);
    }

    /**
     * 执行文件还原的后置操作
     * @param context
     */
    private void afterRestore(RestoreContext context) {
        FileRestoreEvent fileRestoreEvent = new FileRestoreEvent(this,context.getFileIdList());
        applicationContext.publishEvent(fileRestoreEvent);
    }

    /**
     * 执行文件还原操作
     * @param context
     */
    private void doRestore(RestoreContext context) {
        List<RPanUserFile> records = context.getRecords();
        for (RPanUserFile record : records) {
            record.setDelFlag(DelFlagEnum.No.getCode());
            record.setUpdateUser(context.getUserId());
            record.setUpdateTime(new Date());
        }
        boolean updateFlag = rPanUserFileService.updateBatchById(records);
        if(!updateFlag){
            throw new RPanBusinessException("文件还原失败");
        }
    }

    /**
     * 检查文件是不是可以还原
     * @param context
     */
    private void checkRestoreFilename(RestoreContext context) {
        List<RPanUserFile> records = context.getRecords();
        Set<String> filenameSet = records.stream().map(record -> record.getFilename() + RPanConstants.COMMON_SEPARATOR + record.getParentId()).collect(Collectors.toSet());
        if(filenameSet.size()!=records.size()){
            throw new RPanBusinessException("文件还原失败,该还原文件中存在同名文件,请逐个还原并重命名");
        }
        for (RPanUserFile record : records) {
            QueryWrapper queryWrapper = Wrappers.query();
            queryWrapper.eq("user_id",context.getUserId());
            queryWrapper.eq("parent_id",record.getParentId());
            queryWrapper.eq("filename",record.getFilename());
            queryWrapper.eq("del_flag",DelFlagEnum.No.getCode());
            if(rPanUserFileService.count(queryWrapper)>0){
                throw new RPanBusinessException("文件:"+record.getFilename()+"还原失败,该文件夹下面已存在了相同名称的文件或文件夹,请重命名后再次执行还原操作");
            }
        }
    }

    /**
     * 检验文件还原的操作权限
     * @param context
     */
    private void checkRestorePermission(RestoreContext context) {
        List<Long> fileIdList = context.getFileIdList();
        List<RPanUserFile> records = (List<RPanUserFile>) rPanUserFileService.listByIds(fileIdList);
        if(CollectionUtils.isEmpty(records)){
            throw new RPanBusinessException("文件还原失败");
        }
        Set<Long> userIdSet = records.stream().map(RPanUserFile::getUserId).collect(Collectors.toSet());
        if(userIdSet.size()>1){
            throw new RPanBusinessException("你无权操作该文件");

        }
        if (!userIdSet.contains(context.getUserId())) {
            throw new RPanBusinessException("您无权执行文件还原");
        }
        context.setRecords(records);
    }
}
